package at.jku.se.fastsell.data;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

import at.jku.se.fastsell.db4o.DatabaseException;
import at.jku.se.fastsell.db4o.TransactionManager;
import at.jku.se.fastsell.db4o.transactions.ClearDatabaseTransaction;
import at.jku.se.fastsell.db4o.transactions.GetAllAuctionsTransaction;
import at.jku.se.fastsell.db4o.transactions.GetAllUsersTransaction;
import at.jku.se.fastsell.db4o.transactions.StoreAuctionTransaction;
import at.jku.se.fastsell.db4o.transactions.StoreUserTransaction;

/**
 * General class for data access
 */
public class DataAccess {

	private static final Logger LOG = Logger.getLogger(DataAccess.class.getName());

	// ----------------------------------------------------------------------------------

	// *** Management and testing methods ***
	public static void clearDatabase() throws DatabaseException {
		LOG.info("Clearing database...");
		TransactionManager.run(new ClearDatabaseTransaction());
	}

	public static void fillWithSampleData() throws DatabaseException {
		clearDatabase();

		LOG.info("Persiting sample data...");
		for (Auction a : SampleDataProvider.getAuctions()) {
			TransactionManager.run(new StoreAuctionTransaction(a));
		}
	}

	// ----------------------------------------------------------------------------------

	public static List<Auction> getAllAuctions() {
		List<Auction> auctions = new LinkedList<Auction>();
		// --
		try {
			auctions = TransactionManager.run(new GetAllAuctionsTransaction());
		} catch (DatabaseException e) {
			LOG.severe("Could not retrieve all auctions: " + e.toString());
		}
		return auctions;
		// return SampleDataProvider.getAuctions();
	}

	public static List<User> getAllUsers() {
		List<User> users = new LinkedList<User>();
		// --
		try {
			users = TransactionManager.run(new GetAllUsersTransaction());
		} catch (DatabaseException e) {
			LOG.severe("Could not retrieve all users: " + e.toString());
		}
		return users;
		// return SampleDataProvider.getUsers();
	}

	// ----------------------------------------------------------------------------------

	public static Auction createAuction(String title, String description, String seller, double startingPrice, int duration)
			throws DatabaseException {
		// TODO data validation (price not negative, ...)

		Auction a = new Auction(generateAuctionID(), title, description, getUserByName(seller), startingPrice, duration);
		// SampleDataProvider.addAuction(a);

		TransactionManager.run(new StoreAuctionTransaction(a));

		return a;
	}

	public static Auction placeBid(Auction auction, double price, String username) throws DatabaseException {
		try {
			User user = getUserByName(username);
			if (auction.addBid(user, price)) {
				return auction;
			} else {
				throw new DatabaseException("Please check your bid price");
			}
		} catch (Exception e) {
			throw new DatabaseException("Was not able to place bid, please try again", e);
		}
	}

	public static void createUser(String username, String password) throws DatabaseException {
		// TODO data validation (password not empty)
		if (checkIfUserExists(username)) {
			throw new DatabaseException("User already exists");
		}

		User u = new User(username, password);
		TransactionManager.run(new StoreUserTransaction(u));
	}

	private static User getUserByName(String username) throws DatabaseException {
		for (User u : getAllUsers()) {
			if (u.getName().equals(username)) {
				return u;
			}
		}
		throw new DatabaseException("No user found with name " + username);
	}

	public static boolean verifyUser(String username, String password) {
		try {
			User u = getUserByName(username);
			if (u.getPassword().equals(password)) {
				return true;
			}
		} catch (Exception e) {
			LOG.warning("Could not verify user " + username);
		}
		return false;
	}

	public static boolean checkIfUserExists(String name) {
		List<User> users = getAllUsers();
		for (User us : users) {
			if (us.getName().equals(name))
				return true;
		}
		return false;
	}

	// ----------------------------------------------------------------------------------

	public static Auction getAuctionByID(long auctionID) throws DatabaseException {
		for (Auction a : getAllAuctions()) {
			if (a.getAuctionID() == auctionID) {
				return a;
			}
		}
		throw new DatabaseException("No auction found with ID " + auctionID);
	}

	private static boolean checkIfAuctionExists(long auctionID) {
		for (Auction a : getAllAuctions()) {
			if (a.getAuctionID() == auctionID)
				return true;
		}
		return false;
	}

	// ----------------------------------------------------------------------------------

	private static long generateAuctionID() {
		Random r = new Random();
		long id = r.nextLong();

		while (checkIfAuctionExists(id)) {
			id = r.nextLong();
		}
		return id;
	}

}
